﻿using Ardalis.GuardClauses;
using DDD.Application.DBConnectionFactory;
using DDD.Application.Options;
using DDD.Application.Servieces;
using DDD.Common;
using DDD.Common.Const;
using DDD.Core.CQRS;
using DDD.Core.DependencyInjection;
using DDD.Core.Vaildate;
using DDD.Domain.Abstract.Transactions;
using DDD.Infrastructure;
using MassTransit;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Minio;
using System.Reflection;
using Volo.Abp.Modularity;

namespace DDD.Application;

[DependsOn(typeof(InstrastrutureModule), typeof(CommonMoudle))]
public sealed class ApplicationModule : AbpModule
{

    public override void PreConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.Configure<RabbitMqOption>(option =>
        {
            context.Services.GetConfiguration().GetSection(nameof(AppSettingsConst.RabbitMq)).Bind(option, op =>
            {
                op.BindNonPublicProperties = true;
            });
        });

        context.Services.Configure<MinIOOption>(option =>
        {
            context.Services.GetConfiguration().GetSection(nameof(AppSettingsConst.MinIO)).Bind(option, op =>
            {
                op.BindNonPublicProperties = true;
            });
        });

        context.Services.Configure<CQRSOption>(option =>
        {
            option.Assemblies = [Assembly.GetExecutingAssembly()];
            option.BehaviorTypes = [typeof(TransactionBehavior<,>)];
        });

        context.Services.Configure<ValidateOption>(option =>
        {
            option.Assembly = Assembly.GetCallingAssembly();
        });
    }

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        AddDbConnectionFactory(context.Services, context.Services.GetConfiguration());
        AddMinIO(context.Services);
        AddRabbitMqEventBus(context.Services);
    }

    /// <summary>
    /// 添加数据库连接
    /// </summary>
    /// <param name="services"></param>
    /// <param name="configuration"></param>
    /// <returns></returns>
    private IServiceCollection AddDbConnectionFactory(IServiceCollection services, IConfiguration configuration)
    {
        var connectionString = Guard.Against.ConfigurationValueNotIsNullOrEmpty(configuration.GetConnectionString(AppSettingsConst.ConnectionString.READ)!, AppSettingsConst.ConnectionString.READ);

        services.AddScoped<IDBConnectionFactory, MySqlDBConnectionFactory>(c => new MySqlDBConnectionFactory(connectionString));

        return services;
    }

    /// <summary>
    /// 添加MinIO
    /// </summary>
    /// <param name="services"></param>
    /// <param name="configuration"></param>
    /// <returns></returns>
    private IServiceCollection AddMinIO(IServiceCollection services)
    {
        var option = IOC.GetOption<MinIOOption>();

        var minIOClient = new MinioClient()
            .WithEndpoint(option.EndPoint)
            .WithCredentials(option.AccessKey, option.SerectKey)
            .Build();

        services.AddSingleton<IMinioClient>(minIOClient);
        services.AddScoped<MinIOService>();

        return services;
    }

    /// <summary>
    /// 添加RabbitMq
    /// </summary>
    /// <param name="services"></param>
    /// <returns></returns>
    private IServiceCollection AddRabbitMqEventBus(IServiceCollection services)
    {
        var rabbitMqOption = IOC.GetOption<RabbitMqOption>();

        services.AddMassTransit(option =>
        {
            option.UsingRabbitMq((context, conf) =>
            {
                conf.Host(rabbitMqOption.Host, rabbitMqOption.VirtualHost, rconf =>
                {
                    rconf.Username(rabbitMqOption.UserName);
                    rconf.Password(rabbitMqOption.Password);
                });

                conf.ConfigureEndpoints(context);
            });

        });

        return services;
    }
}

